from keras.applications.vgg16 import VGG16
from keras import backend as K
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input, decode_predictions
import numpy as np
import cv2
import matplotlib
matplotlib.use('Agg')
from  matplotlib import pyplot as plt


if __name__ == '__main__':
    print('heat map')
    K.clear_session()
    model = VGG16(weights='./vgg16_weights_tf_dim_ordering_tf_kernels.h5')
    model.summary()
    # 此处是导入你想处理的照片的地址（如果照片和vgg16文件还有你写的代码文件在同一个存储路径的话，此处只需要写照片的名称）
    img_path = 'Goose_QP35-001.jpeg'
    # img_path = 'Boxing_QP16-010.jpeg'
    # 此处的target_size只能是224*224的，因为vgg16模型的结构中，规定的导入图片的大小就是224*224的
    img = image.load_img(img_path, target_size=(224, 224))
    # 将图片信息转换为数组的形式
    x = image.img_to_array(img)
    # 为数组添加维度
    x = np.expand_dims(x, axis=0)
    x = preprocess_input(x)
    #调用vgg16模型
    preds = model.predict(x)
    print('Predicted:', decode_predictions(preds, top=3)[0])
    print(np.argmax(preds[0]))
    #这行代码的解释是：大象这个图像分类位于vgg16这个模型中的第386个索引位置上
    #也就是说如果你input的图像是其他的动物，这个386这个值你是需要自己去改的，就按照上面print(np.argmax(preds[0]))代码输出的值去改就可以了
    african_elephant_output = model.output[:, 386]
    # 看我上面的vgg16模型的结构图，这行代码意思是获取最后一个卷积层的信息（经过验证，获取最后一个卷积层的信息是最好的）
    last_conv_layer = model.get_layer('block5_conv3')
    grads = K.gradients(african_elephant_output, last_conv_layer.output)[0]
    pooled_grads = K.mean(grads, axis=(0, 1, 2))
    iterate = K.function([model.input], [pooled_grads, last_conv_layer.output[0]])
    pooled_grads_value, conv_layer_output_value = iterate([x])
    #这行代码我们可以理解为：获取最后一个卷积层的512个通道的信息，并把这些信息存储在一个列表里
    for i in range(512):
        conv_layer_output_value[:, :, i] *= pooled_grads_value[i]
    #此处是导入matplotlib模块如果不成功的话，你可以按照这三行代码来import matpotlib
    #这里你可以理解为是取倒数第二层的那512个通道信息的均值
    heatmap = np.mean(conv_layer_output_value, axis=-1)
    #这里你可以print一下heatmap，会输出14个数组，每个数组有14个元素
    print(heatmap)
    plt.matshow(heatmap)
    plt.savefig('bob1.png')
    # =================================================
    # =================================================
    heatmap = np.maximum(heatmap, 0)
    heatmap /= np.max(heatmap)
    #这三行代码的意思是把数组转换为图片输出，图片的名字你自己定
    plt.matshow(heatmap)
    plt.savefig('bob1.png')
    # =================================================
    # =================================================
    # 用cv2导入我们上面的热图
    img = cv2.imread(img_path)
    # 将热图变成和原图一样的大小
    heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))
    heatmap = np.uint8(255 * heatmap)
    # 将热图和原图重叠在一起
    heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
    superimposed_img = heatmap * 0.4 + img
    # 保存最后的结果图，图片名字你自己定
    cv2.imwrite('24.jpg', superimposed_img)
